package com.daffodil.core.dao.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.Query;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import com.daffodil.core.dao.JpaDao;
import com.daffodil.core.dao.helper.DaoHelper;
import com.daffodil.core.entity.BaseEntity;
import com.daffodil.core.entity.Page;
import com.daffodil.core.exception.BusinessException;

/**
 * 
 * @author yweijian
 * @date 2022年6月9日
 * @version 2.0.0
 * @description
 */
@Repository("integerJpaDao")
public class IntegerJpaDaoImpl implements JpaDao<Integer> {
    
    @Autowired
    private EntityManager entityManager;

    private static int DEFAULT_PAGE_NUM  = 1;

    private static int DEFAULT_PAGE_SIZE  = 9999;

    public Integer save(BaseEntity<Integer> entity) throws BusinessException {
        Assert.notNull(entity, "[JPA] 实体entity不能为空");
        try {
            this.entityManager.persist(entity);
            return entity.getId();
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
    }

    public void delete(BaseEntity<Integer> entity) throws BusinessException {
        Assert.notNull(entity, "[JPA] 实体entity不能为空");
        try {
            this.entityManager.remove(this.entityManager.contains(entity) ? entity : this.entityManager.merge(entity));
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
    }

    public void delete(BaseEntity<Integer>[] entitys) throws BusinessException {
        Assert.notEmpty(entitys, "[JPA] 实体entitys不能为空");
        for (int i = 0; i < entitys.length; i++) {
            this.delete(entitys[i]);
        }
    }

    public void delete(List<?> entitys) throws BusinessException {
        Assert.notEmpty(entitys, "[JPA] 实体entitys不能为空");
        try {
            for (int i = 0; i < entitys.size(); i++) {
                Object entity = entitys.get(i);
                this.entityManager.remove(this.entityManager.contains(entity) ? entity : this.entityManager.merge(entity));
            }
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
    }

    @SuppressWarnings("unchecked")
    public void delete(Class<?> clazz, Integer id) throws BusinessException {
        Assert.notNull(id, "[JPA] 实体主键id不能为空");
        try {
            BaseEntity<Integer> entity = (BaseEntity<Integer>) clazz.getDeclaredConstructor().newInstance();
            entity.setId(id);
            this.entityManager.remove(this.entityManager.contains(entity) ? entity : this.entityManager.merge(entity));
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
    }

    public void delete(Class<?> clazz, Integer[] ids) throws BusinessException {
        Assert.notEmpty(ids, "[JPA] 实体主键ids不能为空");
        for (int i = 0; i < ids.length; i++) {
            this.delete(clazz, ids[i]);
        }
    }

    public void delete(String hql) throws BusinessException {
        this.execute(hql, null);
    }

    public void delete(String hql, Object para) throws BusinessException {
        List<Object> paras = new ArrayList<Object>();
        paras.add(para);
        this.execute(hql, paras);
    }

    public void delete(String hql, List<Object> paras) throws BusinessException {
        this.execute(hql, paras);
    }

    public void update(String hql) throws BusinessException {
        this.execute(hql, null);
    }

    public void update(String hql, Object para) throws BusinessException {
        List<Object> paras = new ArrayList<Object>();
        paras.add(para);
        this.execute(hql, paras);
    }

    public void update(String hql, List<Object> paras) throws BusinessException {
        this.execute(hql, paras);
    }

    @SuppressWarnings("unchecked")
    public void update(BaseEntity<Integer> entity) throws BusinessException {
        try {
            BaseEntity<Integer> baseEntity = this.find(entity.getClass(), entity.getId());
            baseEntity = (BaseEntity<Integer>) DaoHelper.combineBean(entity, baseEntity);
            this.entityManager.merge(baseEntity);
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
    }

    public void updateAll(BaseEntity<Integer> entity) throws BusinessException {
        try {
            if (!this.entityManager.contains(entity)) {
                this.entityManager.merge(entity);
            }
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
    }

    public void execute(String hql, List<Object> paras) throws BusinessException {
        try {
            String queryHql = DaoHelper.getQueryHql(hql);
            Query query = this.entityManager.createQuery(queryHql);
            DaoHelper.setQueryParas(query, paras);
            query.executeUpdate();
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T find(Class<?> clazz, Integer id) throws BusinessException {
        Assert.notNull(id, "[JPA] 参数id不能为空");
        T entity = null;
        try {
            entity = (T) this.entityManager.find(clazz, id);
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
        return entity;
    }

    public <T> T find(String hql, Class<?> clazz) throws BusinessException {
        return this.find(hql, null, clazz);
    }

    public <T> T find(String hql, Object para, Class<?> clazz) throws BusinessException {
        List<Object> paras = new ArrayList<Object>();
        paras.add(para);
        return this.find(hql, paras, clazz);
    }

    @SuppressWarnings("unchecked")
    public <T> T find(String hql, List<Object> paras, Class<?> clazz) throws BusinessException {
        T entity = null;
        try {
            String queryHql = DaoHelper.getQueryHql(hql);
            Query query = this.entityManager.createQuery(queryHql, clazz);
            DaoHelper.setQueryParas(query, paras);
            List<T> result = query.getResultList();
            Iterator<T> iterator = result.iterator();
            if (iterator.hasNext()) {
                entity = iterator.next();
            }
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
        return entity;
    }
    
    public <T> T find(String hql, Class<?> clazz, LockModeType type) throws BusinessException {
        return this.find(hql, null, clazz, type);
    }

    public <T> T find(String hql, Object para, Class<?> clazz, LockModeType type) throws BusinessException {
        List<Object> paras = new ArrayList<Object>();
        paras.add(para);
        return this.find(hql, paras, clazz, type);
    }

    @SuppressWarnings("unchecked")
    public <T> T find(String hql, List<Object> paras, Class<?> clazz, LockModeType type) throws BusinessException {
        T entity = null;
        try {
            String queryHql = DaoHelper.getQueryHql(hql);
            Query query = this.entityManager.createQuery(queryHql, clazz);
            query.setLockMode(type);
            DaoHelper.setQueryParas(query, paras);
            List<T> result = query.getResultList();
            Iterator<T> iterator = result.iterator();
            if (iterator.hasNext()) {
                entity = iterator.next();
            }
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
        return entity;
    }

    public <T> List<T> search(String hql, Class<?> clazz, Page page) throws BusinessException {
        return this.search(hql, null, clazz, page, null);
    }

    public <T> List<T> search(String hql, Object para, Class<?> clazz, Page page) throws BusinessException {
        List<Object> paras = new ArrayList<Object>();
        paras.add(para);
        return this.search(hql, paras, clazz, page, null);
    }

    public <T> List<T> search(String hql, List<Object> paras, Class<?> clazz, Page page) throws BusinessException {
        return this.search(hql, paras, clazz, page, null);
    }

    @SuppressWarnings("unchecked")
    public <T> List<T> search(String hql, List<Object> paras, Class<?> clazz, Page page, String distinctField) throws BusinessException {
        if(null == page){
            page = new Page();
            page.setPageNumber(DEFAULT_PAGE_NUM);
            page.setPageSize(DEFAULT_PAGE_SIZE);
        }
        page.setTotalRow(this.count(hql, paras, distinctField));
        List<T> list = null;
        try {
            String queryHql = DaoHelper.getQueryHql(hql);
            Query query = this.entityManager.createQuery(queryHql, clazz);
            DaoHelper.setQueryParas(query, paras);
            query.setFirstResult(page.getFromIndex()).setMaxResults(page.getPageSize());
            list = query.getResultList();
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
        return list;
    }

    public <T> List<T> search(String hql, Class<?> clazz) throws BusinessException {
        return this.search(hql, null, clazz);
    }

    public <T> List<T> search(String hql, Object para, Class<?> clazz) throws BusinessException {
        List<Object> paras = new ArrayList<Object>();
        paras.add(para);
        return this.search(hql, paras, clazz);
    }

    @SuppressWarnings("unchecked")
    public <T> List<T> search(String hql, List<Object> paras, Class<?> clazz) throws BusinessException {
        List<T> list = null;
        try {
            String queryHql = DaoHelper.getQueryHql(hql);
            Query query = this.entityManager.createQuery(queryHql, clazz);
            DaoHelper.setQueryParas(query, paras);
            list = query.getResultList();
        } catch (Exception e) {
            throw new BusinessException("[JPA] 执行HQL语句错误 ...", e);
        }
        return list;
    }

    public int count(String hql) throws BusinessException {
        return this.count(hql, null, null);
    }

    public int count(String hql, Object para) throws BusinessException {
        List<Object> paras = new ArrayList<Object>();
        paras.add(para);
        return this.count(hql, paras, null);
    }

    public int count(String hql, List<Object> paras) throws BusinessException {
        return this.count(hql, paras, null);
    }

    public int count(String hql, List<Object> paras, String distinctField) throws BusinessException {
        try {
            String queryHql = DaoHelper.getQueryHql(hql);
            String queryCountHql = DaoHelper.getQueryCountHql(queryHql, distinctField);
            Query query = this.entityManager.createQuery(queryCountHql);
            DaoHelper.setQueryParas(query, paras);
            return ((Long) query.getResultList().iterator().next()).intValue();
        } catch (Exception e) {
            throw new BusinessException("[JPA] 数据统计总数错误 ...", e);
        }
    }
    
}
